/**
  **************************************************************************
  * @file     i2c.c
  * @version  v1.1.0
  * @date     2025-06-18
  * @brief    i2c初始化配置
  **************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "./i2c/i2c.h"


/**
 * @brief       初始化IIC
 * @param       无
 * @retval      无
 */
void iic_init(void)
{
	gpio_init_type gpio_init_struct;
	
    crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
	gpio_default_para_init(&gpio_init_struct);
	
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE; 
	gpio_init_struct.gpio_pins = GPIO_PINS_3;
	gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;		//推挽输出
	gpio_init(GPIOD, &gpio_init_struct);
	
	gpio_init_struct.gpio_pins = GPIO_PINS_6;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;	//开漏输出
	gpio_init(GPIOC, &gpio_init_struct);

    iic_stop();
}

/**
 * @brief       IIC延时函数,用于控制IIC读写速度
 * @param       无
 * @retval      无
 */
static void iic_delay(void)
{
    Delay_us(2);    /* 2us的延时, 读写速度在250Khz以内 */
}

/**
 * @brief       产生IIC起始信号
 * @param       无
 * @retval      无
 */
void iic_start(void)
{
    IIC_SDA_H;
    IIC_SCL_H;
    iic_delay();
    IIC_SDA_L;     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL_L;     /* 钳住I2C总线，准备发送或接收数据 */
    iic_delay();
}

/**
 * @brief       产生IIC停止信号
 * @param       无
 * @retval      无
 */
void iic_stop(void)
{
    IIC_SDA_L;     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL_H;
    iic_delay();
    IIC_SDA_H;     /* 发送I2C总线结束信号 */
    iic_delay();
}

/**
 * @brief       等待应答信号到来
 * @param       无
 * @retval      1，接收应答失败
 *              0，接收应答成功
 */
uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;

    IIC_SDA_H;     /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    iic_delay();
    IIC_SCL_H;     /* SCL=1, 此时从机可以返回ACK */
    iic_delay();

    while (IIC_READ_SDA) {    /* 等待应答 */
        waittime++;
        if (waittime > 250) {
            iic_stop();
            rack = 1;
            break;
        }
    }

    IIC_SCL_L;     /* SCL=0, 结束ACK检查 */
    iic_delay();
    return rack;
}

/**
 * @brief       产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_ack(void)
{
    IIC_SDA_L;     /* SCL 0 -> 1  时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL_H;     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL_L;
    iic_delay();
    IIC_SDA_H;     /* 主机释放SDA线 */
    iic_delay();
}

/**
 * @brief       不产生ACK应答
 * @param       无
 * @retval      无
 */
void iic_nack(void)
{
    IIC_SDA_H;     /* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    iic_delay();
    IIC_SCL_H;     /* 产生一个时钟 */
    iic_delay();
    IIC_SCL_L;
    iic_delay();
}

/**
 * @brief       IIC发送一个字节
 * @param       data: 要发送的数据
 * @retval      无
 */
void iic_send_byte(uint8_t data)
{
    uint8_t t;
    
    for (t = 0; t < 8; t++) {
		if ((data & 0x80) >> 7) IIC_SDA_H;
		else IIC_SDA_L;	/* 高位先发送 */
        iic_delay();
        IIC_SCL_H;
        iic_delay();
        IIC_SCL_L;
        data <<= 1;		/* 左移1位,用于下一次发送 */
    }
    IIC_SDA_H;			/* 发送完成, 主机释放SDA线 */
}

/**
 * @brief       IIC读取一个字节
 * @param       ack:  ack=1时，发送ack; ack=0时，发送nack
 * @retval      接收到的数据
 */
uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;

    for (i = 0; i < 8; i++ ) {    /* 接收1个字节数据 */ 
        receive <<= 1;  /* 高位先输出,所以先收到的数据位要左移 */
        IIC_SCL_H;
        iic_delay();

        if (IIC_READ_SDA) {
            receive++;
        }
        
        IIC_SCL_L;
        iic_delay();
    }

    if (!ack) {
        iic_nack();     /* 发送nACK */
    } else {
        iic_ack();      /* 发送ACK */
    }

    return receive;
}

